package image.processing;

/*
 * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   - Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   - Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 *   - Neither the name of Oracle or the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

import image.edge.SusanEdgeDetector;
import image.edge.SusanEdgeDetector.SUSAN_TYPES;
import image.filter.GaussianFilter;
import image.filter.HighPassFilter;
import image.filter.MeanFilter;
import image.filter.MedianFilter;
import image.generators.ShapesGenerators;
import image.lines.Hough;
import image.lines.HoughCircles;
import image.noise.generators.BlankAdditiveGaussianNoise;
import image.noise.generators.MultiplicativeExponentialNoise;
import image.noise.generators.SaltAndPepperNoise;
import image.threshold.GlobalThresholder;
import image.threshold.OtsuThresholderA;
import image.utils.Degrade;
import image.utils.ImageUtilitiesImpl;

import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;

import javax.imageio.ImageIO;
import javax.swing.JFrame;

//import net.sf.image4j.codec.bmp.BMPDecoder;

/**
 * This class demonstrates how to load an Image from an external file
 */
public class LoadImageApp extends Component {

	private static String FileMenu = "File";
	private static String FileMenuLoadImage = "Load Image";
	private static String FileMenuQuit = "Quit";

	BufferedImage img;

	public void paint(Graphics g) {
		g.drawImage(img, 0, 0, null);
	}

	private static void save(BufferedImage image, String name) {
		String fileName = name;
		File file = null;
		try {
			file = new File(fileName + "." + "raw");
			if (image.getType() == BufferedImage.TYPE_BYTE_GRAY) {
				FileWriter writer = new FileWriter(file);
				for (int x = 0; x < image.getWidth(); x++) {
					for (int y = 0; y < image.getHeight(); y++) {
						writer.write(image.getRaster().getSample(x, y, 0));
					}
				}

			}
			String ext = "jpg";
			file = new File(fileName + "." + ext);
			ImageIO.write(image, ext, file); // ignore returned boolean

		} catch (IOException e) {
			System.out.println("Write error for " + file.getPath() + ": "
					+ e.getMessage());
		}
	}

	public LoadImageApp(String fileName) {
		try {
			BufferedImage lena = createImage(getBytesFromFile(new File(
					"LENA.RAW")), 256, 256, false);
			BufferedImage girl = createImage(getBytesFromFile(new File(
					"GIRL.RAW")), 389, 164, false);
			BufferedImage girl2 = createImage(getBytesFromFile(new File(
					"GIRL2.RAW")), 256, 256, false);
			BufferedImage i070 = createImage(getBytesFromFile(new File(
					"0-70.RAW")), 256, 256, false);
			BufferedImage yo = ImageIO.read(new File("IMG_0929.JPG"));
			BufferedImage cuatropuntospng = ImageIO.read(new File("4puntosnegros.png"));
			BufferedImage cuatropuntosraw = createImage(getBytesFromFile(new File(
					"4puntos.raw")), 360,520, false);
			//BufferedImage mateoValen = BMPDecoder.read(new File("MateoValenGray2.bmp"));
			//System.out.println("mateo y valen" + mateoValen.getType());
			BufferedImage test = openPgmImage(new File("TEST.PGM"),false);
//			BufferedImage yo2 = ImageIO.read(new File("IMG_0937.JPG"));
			BufferedImage blanco = ImageIO.read(new File("blanco.jpg"));
			BufferedImage negroblanco = ImageIO
					.read(new File("negroblango.jpg"));
			BufferedImage negroblancogrande = ImageIO.read(new File(
					"blanconegro.jpg"));

			// img = ImageProcessor.addSalta( lena,girl2);
			BufferedImage negative = ImageProcessor.negative(yo);
			BufferedImage scalar = ImageProcessor.scalarProduct(lena, 1,
					ImageProcessor.CompressAlgorithm.LINEAR);
	//		BufferedImage productImages = ImageProcessor.product(yo, yo2,
		//			ImageProcessor.CompressAlgorithm.DYNAMIC);
			BufferedImage sumImages = ImageProcessor.add(girl2, lena,
					ImageProcessor.CompressAlgorithm.LINEAR);
			BufferedImage subImages = ImageProcessor.add(girl2, lena,
					ImageProcessor.CompressAlgorithm.LINEAR);
			BufferedImage umbral = ImageProcessor.threshold(yo, 128);

			MultiplicativeExponentialNoise noiser = new MultiplicativeExponentialNoise(
					0.0000002);
			BufferedImage lenaExponencial = noiser.addNoise(lena,
					ImageProcessor.CompressAlgorithm.LINEAR);
			BlankAdditiveGaussianNoise gaussianNoiser = new BlankAdditiveGaussianNoise(
					128, 0);
			BufferedImage lenaGaussiana = gaussianNoiser.addNoise(lena,
					ImageProcessor.CompressAlgorithm.LINEAR,10);
			SaltAndPepperNoise saltNoiser = new SaltAndPepperNoise(0.02, 0.89);
			BufferedImage lenaSaltyPimienta = saltNoiser.addNoise(lena,
					ImageProcessor.CompressAlgorithm.JAVADEFAULT);
			MeanFilter filter = new MeanFilter(5);
			BufferedImage yomedio  = filter.applyFilter(yo,ImageProcessor.CompressAlgorithm.LINEAR);
			MedianFilter filtermedian = new MedianFilter(3);
			BufferedImage lenamediana  = filtermedian.applyFilter(lena,ImageProcessor.CompressAlgorithm.LINEAR);
			HighPassFilter pasaltofilter = new HighPassFilter(3);
			BufferedImage lenaalteda  = pasaltofilter.applyFilter(lena,ImageProcessor.CompressAlgorithm.LINEAR);
			BufferedImage degrade = Degrade.generateDegrade(500,400);
			//BufferedImage degradeColor = Degrade.generateDegrade(500,400,127,24,88);
			save(lenaSaltyPimienta, "lenascalar");
			GaussianFilter gausianFilter = new GaussianFilter(1);
			BufferedImage lenagauseanafiltrada  = gausianFilter.applyFilter(lenaGaussiana,ImageProcessor.CompressAlgorithm.LINEAR);
			System.out.println(lena.getType() + "<-- lena type");
		/*	AEdgeDetector aedge = new AEdgeDetector(test);
			BufferedImage edged = aedge.FindEdges();
			BKirshEdgeDetector	 bedge = new BKirshEdgeDetector(test);
			BufferedImage edged2 = bedge.FindEdges();
			CEdgeDetector cedge = new CEdgeDetector(test);
			BufferedImage edged3 = cedge.FindEdges();
			DEdgeDetector dedge = new DEdgeDetector(test);
			BufferedImage edged4 = dedge.FindEdges();
			*/
			/*SusanEdgeDetector susan = new SusanEdgeDetector(test, 27, SUSAN_TYPES.CORNERS, 0.3f,true);
			BufferedImage corners = susan.FindEdges();
			 BufferedImage dospuntos = ImageUtilitiesImpl.getInstance().openPgmImage(new File("3puntos.pgm"),false);
			*/
		/*	Hough hough = new Hough(1000, 1000, 1, dospuntos,20);
			BufferedImage lines = hough.findLines();*/
			 //BufferedImage uncirculo = ImageUtilitiesImpl.getInstance().openPgmImage(new File("uncirculo.pgm"),false);
			 /*BufferedImage uncirculo = ImageIO.read(new File("japanese_coins.png"));
			 SusanEdgeDetector susan2 = new SusanEdgeDetector(uncirculo, 27, SUSAN_TYPES.BOTH, 0.3f,false);;
			 BufferedImage bordes = susan2.FindEdges();
			HoughCircles houghC = new HoughCircles(100,100,100, 20, bordes,20);
			BufferedImage circulo = houghC.findCircles();
			System.out.println("here");
*/
			/*utils.saveImage(new File("edged1.jpg"), edged);
			utils.saveImage(new File("edged2.jpg"), edged2);
			utils.saveImage(new File("edged3.jpg"), edged3);
			utils.saveImage(new File("edged4.jpg"), edged4);
			*/
			/*GlobalThresholder gt = new GlobalThresholder();
			int thresholdGlobal = gt.findThresholdValue(mateoValen);
			BufferedImage mateoyvalen = ImageProcessor.threshold(mateoValen, thresholdGlobal);
			System.out.println("mateo y vale varianza: " + thresholdGlobal);
			OtsuThresholderA ot = new OtsuThresholderA();
			int umbrallena = ot.doThreshold(mateoValen);
			BufferedImage lenaoptima = ImageProcessor.threshold(mateoValen, umbrallena);
			System.out.println(umbrallena +"maxima varianza para lena");
			 System.out.println(BufferedImage.TYPE_3BYTE_BGR);
			 System.out.println(BufferedImage.TYPE_4BYTE_ABGR);
			 System.out.println(BufferedImage.TYPE_4BYTE_ABGR_PRE);
			 System.out.println(BufferedImage.TYPE_BYTE_BINARY);
			 System.out.println(BufferedImage.TYPE_BYTE_GRAY + "<--- byte gray");
			 System.out.println(BufferedImage.TYPE_BYTE_INDEXED);
			 System.out.println(BufferedImage.TYPE_CUSTOM);
			 System.out.println(BufferedImage.TYPE_INT_ARGB);
			 System.out.println(BufferedImage.TYPE_INT_ARGB_PRE);
			  System.out.println(BufferedImage.TYPE_INT_BGR);
			  System.out.println(BufferedImage.TYPE_USHORT_555_RGB);
			  System.out.println(BufferedImage.TYPE_USHORT_565_RGB);
			  System.out.println(BufferedImage.TYPE_USHORT_GRAY);
			 */
			
			//BufferedImage rect = RectangleGenerator.generateRectangle(128,128,20,20,512,600);
			BufferedImage rect2 = ShapesGenerators.generateRectangle(50,50,512,700);
			BufferedImage square = ShapesGenerators.generateSquare(120, 256,256);
			BufferedImage rectRot = ShapesGenerators.drawCircle(128,128,40,256,256);
			
			
			img = rectRot;

			// img = ImageIO.read(new File("pasto.jpg"));
		} catch (IOException e) {
			e.printStackTrace();
		}

	}
	public BufferedImage openPgmImage(File file, boolean isColor) throws IOException{
		BufferedReader is = new BufferedReader(new FileReader(file));
		String line = is.readLine();
		int height;
		int width;
		int maxGray;
		if(!line.equals("P5")){
			System.err.println("not pgm");
			return null;
		}
		line = is.readLine();
		String[] size = line.split(" ");
		width = Integer.parseInt(size[0]);
		height = Integer.parseInt(size[1]);
		maxGray = Integer.parseInt(is.readLine());
		is.close();

		byte[] bytes = getBytesFromFile(file);
		byte[] byteaux = new byte[width * height];
		for (int i = 0; i < width * height; i++){
			byteaux[i] = bytes[15 + i];
		}
		
		return createImage(byteaux, width, height, isColor);
		
	}


	// Returns the contents of the file in a byte array.
	public static byte[] getBytesFromFile(File file) throws IOException {
		InputStream is = new FileInputStream(file);

		// Get the size of the file
		long length = file.length();

		// You cannot create an array using a long type.
		// It needs to be an int type.
		// Before converting to an int type, check
		// to ensure that file is not larger than Integer.MAX_VALUE.
		if (length > Integer.MAX_VALUE) {
			// File is too large
		}

		// Create the byte array to hold the data
		byte[] bytes = new byte[(int) length];

		// Read in the bytes
		int offset = 0;
		int numRead = 0;
		while (offset < bytes.length
				&& (numRead = is.read(bytes, offset, bytes.length - offset)) >= 0) {
			offset += numRead;
		}

		// Ensure all the bytes have been read in
		if (offset < bytes.length) {
			throw new IOException("Could not completely read file "
					+ file.getName());
		}

		// Close the input stream and return bytes
		is.close();
		return bytes;
	}

	public static BufferedImage createImage(byte rawData[], int width,
			int height, boolean isColor) {

		BufferedImage ret;
		isColor = false;
		if (isColor)
			ret = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
		else
			ret = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);
		WritableRaster raster = ret.getRaster();
		int k = 0;
		for (int i = 0; i < height; i++) {
			for (int j = 0; j < width; j++) {
				if (isColor) {
					raster.setSample(j, i, 0, rawData[k]);
					raster.setSample(j, i, 1, rawData[k + 1]);
					raster.setSample(j, i, 2, rawData[k + 2]);
					k += 2;
				} else
					raster.setSample(j, i, 0, rawData[k]);
				k++;
			}
		}

		return ret;
	}

	public Dimension getPreferredSize() {
		if (img == null) {
			return new Dimension(100, 100);
		} else {
			return new Dimension(img.getWidth(null), img.getHeight(null));
		}
	}

	public static void main(String[] args) {

		JFrame f = new JFrame("Load Image Sample");

		// mBar.add();

		f.addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				System.exit(0);
			}
		});

		f.add(new LoadImageApp("LENA.RAW"));
		f.pack();
		f.setVisible(true);
	}
}
